package com.ruoyi.business.service;

import com.ruoyi.bizsys.domain.*;
import com.ruoyi.bizsys.enums.EnumFeeType;
import com.ruoyi.bizsys.mapper.AccountFlowMapper;
import com.ruoyi.bizsys.mapper.LoanIouMapper;
import com.ruoyi.bizsys.mapper.RepaymentOrderMapper;
import com.ruoyi.bizsys.service.*;
import com.ruoyi.bizsys.utils.BizConstants;
import com.ruoyi.business.domain.LoanRepaymentResult;
import com.ruoyi.business.service.async.AsyncService;
import com.ruoyi.common.constant.LoanConstants;
import com.ruoyi.common.constant.UserConstants;
import com.ruoyi.common.utils.DateUtils;
import com.ruoyi.riskrule.config.RaiseLimitParamsLoader;
import lombok.extern.slf4j.Slf4j;
import org.redisson.api.RLock;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.math.BigDecimal;
import java.util.Calendar;
import java.util.Date;
import java.util.GregorianCalendar;
import java.util.List;

/**
 * @author wqg
 * @description
 * @date 2022/5/12
 */
@Service
@Slf4j
public class DoLoanRepaymentService {
    @Autowired
    ICreditAccountService creditAccountService;

    @Autowired
    ILoanOffsetService loanOffsetService;

    @Autowired
    ILoanIouService loanIouService;
    @Autowired
    LoanIouMapper loanIouMapper;
    @Autowired
    ICustReduceOrderService custReduceOrderService;
    @Autowired
    IRepaymentOrderService repaymentOrderService;
    @Autowired
    ILoanOverflowService iLoanOverflowService;
    @Autowired
    RepaymentOrderMapper repaymentOrderMapper;
    @Autowired
    private RaiseLimitParamsLoader raiseLimitParamsLoader;

    @Autowired
    AsyncService asyncService;

    @Autowired
    AccountFlowMapper accountFlowMapper;

    public boolean doLoanRepaymentGetInfo(LoanOffset loanOffset) {
        log.info("冲账>loanOffset:{}",loanOffset.toString());
        boolean result = false;
        try {
            //获取账户信息
            CreditAccount creditAccount = creditAccountService.getNormalAcountOnLoan(loanOffset.getCustNo());
            dealCreditAccountNullRes(loanOffset, creditAccount);
            result = this.loanOffset(creditAccount, loanOffset);
        } catch (Exception e) {
            log.error("根据冲账记录ID {}，冲账异常", loanOffset.getId(), e);
            loanOffset.setLoanOffsetStatus(BizConstants.LOAN_OFFSET_STATUS_FAIL);
            loanOffset.setLoanOffsetDesc("异常");
            //throw new BusinessException(RspEnmu.LOAN_OFFSET_EXCEPTION);
        } finally {
            loanOffsetService.updateLoanOffset(loanOffset);
        }
        return result;
    }
    public boolean loanOffset(CreditAccount creditAccount, LoanOffset loanOffset) {
        boolean result = false;
        //获取借据
        LoanIou loanIou =loanIouService.getLoanIouByLoanSerialNo(loanOffset.getLoanSerialNo());
        dealIouNUllRes(loanOffset, loanIou);
        //冲账前借据数据记录
        loanOffsetDoSet(loanOffset, loanIou);
        //开始冲账
        LoanRepaymentResult rst = this.doLoanRepaymentDoing(creditAccount, loanIou, loanOffset);
        if (rst.isSucess()) {
            RepaymentOrder repaymentOrder = repaymentOrderService.getDetail(loanOffset.getRepaymentNo());
            if(null!=repaymentOrder.getCustReduceOrderId()){
                // 查询 repayOrder custorderId 是否存在 更新 custoRderid状态
                custReduceOrderService.updateAndAddReduceInfo(repaymentOrder,BizConstants.LOAN_REPAYMENT_ORDER_TYPE_QR_REDUCE);
            }
            loanOffset.setLoanOffsetStatus(BizConstants.LOAN_OFFSET_STATUS_SUCCESS);
            loanOffset.setSurplusAmt(rst.getSurplusAmt());
            result = true;
        } else {
            loanOffset.setLoanOffsetStatus(BizConstants.LOAN_OFFSET_STATUS_FAIL);
        }
        loanOffset.setLoanOffsetDesc(rst.getResultDesc());
        return result;
    }

    @Transactional
    LoanRepaymentResult doLoanRepaymentDoing(CreditAccount creditAccount, LoanIou loanIou, LoanOffset loanOffset) {
        BigDecimal amt = loanOffset.getAmt();

        LoanRepaymentResult rst = new LoanRepaymentResult();
        log.info("客户号{}借据{}开始冲账", creditAccount.getCustNo(), loanIou.getLoanSerialNo());

        //冲账滞纳金
        if (amt.compareTo(BigDecimal.ZERO) > 0) {//如果金额大于0
            //BigDecimal lateFeeNeed = loanIou.getLateFee().subtract(loanIou.getRepaidLateFee()).subtract(loanIou.getFeeRemissionAmt());//还需要还的
            BigDecimal lateFeeNeed = checkOffsetPayTime(loanIou,loanOffset);
            if (lateFeeNeed.compareTo(BigDecimal.ZERO) > 0) {//还需要还
                BigDecimal lateFeeResult = amt.subtract(lateFeeNeed);//冲账滞纳金后
                if (lateFeeResult.compareTo(BigDecimal.ZERO) > 0) {//冲账后》0
                    loanOffset.setOffsetLateFee(lateFeeNeed);
                    loanIou.setRepaidLateFee(loanIou.getLateFee().subtract(loanIou.getFeeRemissionAmt()));
                    amt = lateFeeResult;
                } else {
                    loanOffset.setOffsetLateFee(amt);
                    loanIou.setRepaidLateFee(loanIou.getRepaidLateFee().add(amt));
                    amt = BigDecimal.ZERO;

                }

            }
        }

        //冲账利息
        if (amt.compareTo(BigDecimal.ZERO) > 0) {//如果金额大于0
            BigDecimal need = loanIou.getLoanInterest().subtract(loanIou.getRepaidInterest());//还需要还的
            if (need.compareTo(BigDecimal.ZERO) > 0) {//还需要还
                BigDecimal result = amt.subtract(need);//冲账滞纳金后
                if (result.compareTo(BigDecimal.ZERO) > 0) {//冲账后》0
                    loanOffset.setOffsetInterest(need);
                    loanIou.setRepaidInterest(loanIou.getLoanInterest());
                    amt = result;
                } else {
                    loanOffset.setOffsetInterest(amt);
                    loanIou.setRepaidInterest(loanIou.getRepaidInterest().add(amt));
                    amt = BigDecimal.ZERO;
                }
            }
        }

        //冲账服务费
        if (amt.compareTo(BigDecimal.ZERO) > 0) {//如果金额大于0
            BigDecimal serviceFeeNeed = loanIou.getServiceFee().subtract(loanIou.getRepaidServiceFee());//还需要还的
            if (serviceFeeNeed.compareTo(BigDecimal.ZERO) > 0) {//还需要还
                BigDecimal serviceFeeResult = amt.subtract(serviceFeeNeed);//冲账滞纳金后
                if (serviceFeeResult.compareTo(BigDecimal.ZERO) > 0) {//冲账后》0
                    loanOffset.setOffsetServiceFee(serviceFeeNeed);
                    loanIou.setRepaidServiceFee(loanIou.getServiceFee());
                    amt = serviceFeeResult;
                } else {
                    loanOffset.setOffsetServiceFee(amt);
                    loanIou.setRepaidServiceFee(loanIou.getRepaidServiceFee().add(amt));
                    amt = BigDecimal.ZERO;
                }
            }
        }

        //冲账本金
        if (amt.compareTo(BigDecimal.ZERO) > 0) {//如果金额大于0
            BigDecimal need = loanIou.getLoanPrincipal().subtract(loanIou.getRepaidPrincipal());//还需要还的
            if (need.compareTo(BigDecimal.ZERO) > 0) {//还需要还
                BigDecimal result = amt.subtract(need);//冲账滞纳金后
                if (result.compareTo(BigDecimal.ZERO) > 0) {//冲账后》0
                    loanOffset.setOffsetPrincipal(need);
                    loanIou.setRepaidPrincipal(loanIou.getLoanPrincipal());
                    amt = result;
                } else {
                    loanOffset.setOffsetPrincipal(amt);
                    loanIou.setRepaidPrincipal(loanIou.getRepaidPrincipal().add(amt));
                    amt = BigDecimal.ZERO;
                }
            }
        }

        //多出来的钱
        rst.setSurplusAmt(amt);

       // RepaymentOrder repaymentOrder = iBRepaymentService.getMaxPayTime(loanIou.getLoanSerialNo());
        RepaymentOrder repaymentOrder = repaymentOrderMapper.getMaxPayTime(loanIou.getLoanSerialNo());

        BigDecimal overFlowAmount = BigDecimal.ZERO;
        if (amt.doubleValue() > 0) {
            overFlowAmount = amt;
            LoanOverflow loanOverflow = new LoanOverflow();
            loanOverflow.setChangeAmount(amt);
            loanOverflow.setCustNo(loanOffset.getCustNo());
            loanOverflow.setOverflowTime(repaymentOrder.getPayTime());
            if(repaymentOrder.getActionType().equals("Monnify-Transfer")){
                loanOverflow.setType(BizConstants.OVERFLOW_TYPE_OVERFLOW_TRANSFERTOUS);
            }else{
                loanOverflow.setType(BizConstants.OVERFLOW_TYPE_OVERFLOW_WITHHOLD);
            }

            loanOverflow.setRepaymentOrderNo(loanOffset.getRepaymentNo());
            loanOverflow.setLoanIouNo(loanOffset.getLoanSerialNo());
            iLoanOverflowService.insertLoanOverflow(loanOverflow);

            //修改用户溢缴金额
            // creditAccountService.updateOverflowAmount(repaymentOrder.getCustNo(),amt);

        }

        //更新借据
        BigDecimal needTotal = loanIou.getLoanPrincipal().add(loanIou.getLoanInterest()).add(loanIou.getServiceFee()).add(loanIou.getLateFee()).subtract(loanIou.getFeeRemissionAmt());
        BigDecimal repaidTotal = loanIou.getRepaidPrincipal().add(loanIou.getRepaidInterest()).add(loanIou.getRepaidServiceFee()).add(loanIou.getRepaidLateFee());
        if (needTotal.compareTo(repaidTotal) == 1) {//未结清
            BigDecimal updateResult = needTotal.subtract(repaidTotal);
            //判断当前时间和还款日的关系
            Date repayDate = DateUtils.dateTime(DateUtils.YYYY_MM_DD_SLASH, loanIou.getRepayDate());
            Calendar calendar = new GregorianCalendar();
            calendar.setTime(repayDate);
            calendar.add(calendar.DATE, 1); //把日期往后增加一天
            repayDate = calendar.getTime();
            if (repayDate.before(new Date())) {//逾期
                loanIou.setOverdueAmount(updateResult);
                loanIou.setIouStatus(LoanIou.LOAN_IOU_STATUS_OVERDUE);
            } else {
                loanIou.setIouStatus(LoanIou.LOAN_IOU_STATUS_WAIT);
            }
        } else {//结清
            loanIou.setOverdueAmount(BigDecimal.ZERO);
            loanIou.setIouStatus(LoanIou.LOAN_IOU_STATUS_SETTLE);

            //找到repyamentOrder里时间最大的payTime
            loanIou.setSettleDate(repaymentOrder.getPayTime());

        }
        loanIouService.updateLoanIou(loanIou);

        //更新账户
        this.updateAccount(creditAccount);
        
        // 2022/5/20 账目流水
        createAccountFlow(repaymentOrder,loanOffset,overFlowAmount);

        rst.setSucess(true);
        rst.setResultDesc("success");

        //结清后自动化提额
        if (LoanIou.LOAN_IOU_STATUS_SETTLE == loanIou.getIouStatus()) {
            try {
                RuleIn ruleIn = raiseLimitParamsLoader.initRuleInParam(loanIou.getLoanSerialNo(), creditAccount.getCustNo());
                asyncService.automaticRaiseLimit(loanIou.getLoanSerialNo(), loanIou.getCustNo(), ruleIn);
            } catch (Exception e) {
                log.error("客户号{}借据{}自动化提额异常", loanIou.getCustNo(), loanIou.getLoanSerialNo(), e);
            }
        }

        return rst;
    }

    /**
     * 记录账目流水
     * 减免的，判断减免是哪一项才需要单个记录
     * @param repaymentOrder
     * @param loanOffset
     */
    private void createAccountFlow(RepaymentOrder repaymentOrder, LoanOffset loanOffset,BigDecimal overFlowAmount) {
        AccountFlow accountFlow = new AccountFlow();
        accountFlow.setCustNo(repaymentOrder.getCustNo());
        accountFlow.setRelativeSerialNo(repaymentOrder.getCustReduceOrderId()==null?"": repaymentOrder.getCustReduceOrderId().toString());
        accountFlow.setTransferChannel(loanOffset.getActionType());
        accountFlow.setTransferTime(repaymentOrder.getCreateTime());
        accountFlow.setOffsetTime(loanOffset.getCreateTime());
        accountFlow.setDataSource("repayment_order、loan_offset");

        insertAccountFlowPrincipal(loanOffset, accountFlow);
        insertAccountFlowInterest(loanOffset, accountFlow);
        insertAccountFLowLateFee(loanOffset, accountFlow);
        insertAccountFlowServiceFee(loanOffset, accountFlow);
        insertAccountFlowOverFlow(overFlowAmount, accountFlow);

    }

    /**
     * 账目流水--溢缴款
     * @param overFlowAmount
     * @param accountFlow
     */
    private void insertAccountFlowOverFlow(BigDecimal overFlowAmount, AccountFlow accountFlow) {
        // 判断入账--溢缴款
        if(overFlowAmount.compareTo(BigDecimal.ZERO)>0){
            accountFlow.setAmt(overFlowAmount);
            accountFlow.setFeeType(EnumFeeType.OVERPAY_IN.getCode());
            accountFlowMapper.insertByIndex(accountFlow);
        }
    }


    private void insertAccountFlowServiceFee(LoanOffset loanOffset, AccountFlow accountFlow) {
        // 判断入账--减服务费
        if(loanOffset.getOffsetServiceFee().compareTo(BigDecimal.ZERO)>0){
            accountFlow.setAmt(loanOffset.getOffsetServiceFee());
            accountFlow.setFeeType(EnumFeeType.REPAID_SERVICE_FEE.getCode());
            accountFlowMapper.insertByIndex(accountFlow);
        }
    }

    /**
     * 账目流水--滞纳金
     * @param loanOffset
     * @param accountFlow
     */
    private void insertAccountFLowLateFee(LoanOffset loanOffset, AccountFlow accountFlow) {
        // 判断入账--还款罚息
        if(loanOffset.getOffsetLateFee().compareTo(BigDecimal.ZERO)>0){
            accountFlow.setAmt(loanOffset.getOffsetLateFee());
            accountFlow.setFeeType(EnumFeeType.REPAID_LATE_FEE.getCode());
            accountFlowMapper.insertByIndex(accountFlow);
        }
    }

    /**
     * 记录账目流水-还款利息
     * @param loanOffset
     * @param accountFlow
     */
    private void insertAccountFlowInterest(LoanOffset loanOffset, AccountFlow accountFlow) {
        // 判断入账--还款利息
        if(loanOffset.getOffsetInterest().compareTo(BigDecimal.ZERO)>0){
            accountFlow.setAmt(loanOffset.getOffsetInterest());
            accountFlow.setFeeType(EnumFeeType.REPAID_INTEREST.getCode());
            accountFlowMapper.insertByIndex(accountFlow);
        }
    }

    /**
     * 记录账目流水-还款本金
     * @param loanOffset
     * @param accountFlow
     */
    private void insertAccountFlowPrincipal(LoanOffset loanOffset, AccountFlow accountFlow) {
        // 判断入账--还款本金
        if(loanOffset.getOffsetPrincipal().compareTo(BigDecimal.ZERO)>0){
            accountFlow.setAmt(loanOffset.getOffsetPrincipal());
            accountFlow.setFeeType(EnumFeeType.REPAID_PRINCIPAL.getCode());
            accountFlowMapper.insertByIndex(accountFlow);
        }
    }


    private void loanOffsetDoSet(LoanOffset loanOffset, LoanIou loanIou) {
        loanOffset.setLoanPrincipal(loanIou.getLoanPrincipal());
        loanOffset.setRepaidPrincipal(loanIou.getRepaidPrincipal());
        loanOffset.setLoanInterest(loanIou.getLoanInterest());
        loanOffset.setRepaidInterest(loanIou.getRepaidInterest());
        loanOffset.setServiceFee(loanIou.getServiceFee());
        loanOffset.setRepaidServiceFee(loanIou.getRepaidServiceFee());
        loanOffset.setLateFee(loanIou.getLateFee());
        loanOffset.setRepaidLateFee(loanIou.getRepaidLateFee());
        loanOffset.setReduceAmt(loanIou.getFeeRemissionAmt());
    }

    private void dealIouNUllRes(LoanOffset loanOffset, LoanIou loanIou) {
        if (null== loanIou) {
            String msg = "根据冲账借据号：" + loanOffset.getLoanSerialNo() + "未匹配到借据信息";
            log.error(msg);
            loanOffset.setLoanOffsetDesc(msg);
            loanOffset.setLoanOffsetStatus(BizConstants.LOAN_OFFSET_STATUS_FAIL);
        }
    }

    /**
     * 处理CreditAccount空异常
     * @param loanOffset
     * @param creditAccount
     */
    private void dealCreditAccountNullRes(LoanOffset loanOffset, CreditAccount creditAccount) {
        if (null== creditAccount) {
            String msg = "根据冲账客户号：" + loanOffset.getCustNo() + "未匹配到账户信息";
            log.error(msg);
            loanOffset.setLoanOffsetDesc(msg);
            loanOffset.setLoanOffsetStatus(BizConstants.LOAN_OFFSET_STATUS_FAIL);
        }
    }

    public void updateAccount(CreditAccount creditAccount) {
        //获取账户之前的状态
        String oldOnLoanStr = creditAccount.getOnLoan();

        //获取所有未结清的借据
        List<LoanIou> activeLoanList = loanIouMapper.getActiveLoanIouByCustNo(creditAccount.getCustNo());
        if (activeLoanList.size() < 1) {
            creditAccount.setOnLoan(BizConstants.ACCOUNT_ON_lOAN_STATUS_0);
            creditAccount.setOnLoanActiveDate(null);
        } else {
            if (UserConstants.BUSINESS_NOT_NORMAL.equals(oldOnLoanStr)) {
                creditAccount.setOnLoan(BizConstants.ACCOUNT_ON_lOAN_STATUS_1);
                //设置账户onloan的激活日期
                Calendar calendar = Calendar.getInstance();
                calendar.setTime(new Date());
                calendar.set(Calendar.HOUR_OF_DAY, 0);
                calendar.set(Calendar.MINUTE, 0);
                calendar.set(Calendar.SECOND, 0);
                calendar.set(Calendar.MILLISECOND, 0);
                creditAccount.setOnLoanActiveDate(calendar.getTime());
            }
        }

        //逾期标志
        String isOverdue = "0";
        BigDecimal loanPrincipal = BigDecimal.ZERO;
        BigDecimal repaidPrincipal = BigDecimal.ZERO;
        BigDecimal loanInterest = BigDecimal.ZERO;
        BigDecimal repaidInterest = BigDecimal.ZERO;
        BigDecimal serviceFee = BigDecimal.ZERO;
        BigDecimal repaidServiceFee = BigDecimal.ZERO;
        BigDecimal lateFee = BigDecimal.ZERO;
        BigDecimal repaidLateFee = BigDecimal.ZERO;
        BigDecimal overdueAmount = BigDecimal.ZERO;
        BigDecimal loanQuota = BigDecimal.ZERO;

        for (LoanIou activeLoan : activeLoanList) {
            loanPrincipal = loanPrincipal.add(activeLoan.getLoanPrincipal());
            repaidPrincipal = repaidPrincipal.add(activeLoan.getRepaidPrincipal());
            loanInterest = loanInterest.add(activeLoan.getLoanInterest());
            repaidInterest = repaidInterest.add(activeLoan.getRepaidInterest());
            serviceFee = serviceFee.add(activeLoan.getServiceFee());
            repaidServiceFee = repaidServiceFee.add(activeLoan.getRepaidServiceFee());
            lateFee = lateFee.add(activeLoan.getLateFee());
            repaidLateFee = repaidLateFee.add(activeLoan.getRepaidLateFee());
            overdueAmount = overdueAmount.add(activeLoan.getOverdueAmount());
            if (LoanIou.LOAN_IOU_STATUS_OVERDUE == activeLoan.getIouStatus()) {
                isOverdue = "1";
            }
            //未还金额
            BigDecimal need = activeLoan.getLoanPrincipal().subtract(activeLoan.getRepaidPrincipal());
            loanQuota = loanQuota.add(need);
        }
        creditAccount.setLoanPrincipal(loanPrincipal);
        creditAccount.setRepaidPrincipal(repaidPrincipal);
        creditAccount.setLoanInterest(loanInterest);
        creditAccount.setRepaidInterest(repaidInterest);
        creditAccount.setServiceFee(serviceFee);
        creditAccount.setRepaidServiceFee(repaidServiceFee);
        creditAccount.setLateFee(lateFee);
        creditAccount.setRepaidLateFee(repaidLateFee);
        creditAccount.setOverdueAmount(overdueAmount);
        if (UserConstants.BUSINESS_NORMAL.equals(isOverdue)) {
            creditAccount.setIsOverdue(UserConstants.BUSINESS_NORMAL);
        } else {
            creditAccount.setIsOverdue(UserConstants.BUSINESS_NOT_NORMAL);
        }
        //更新额度
        creditAccount.setLoanQuota(loanQuota);
        creditAccountService.updateCreditAccountRest(creditAccount);
    }







}
